JavaScript基本语法
前置知识
MDN文档 JavaScript的手册方面
<script>
是双标签,必须带上</script>
,如果使用自闭合会无法生效- 一般 JS 代码放在最下面
- 使用 ES6 的代码可能需要使用到 Babel 将 ES6 版本的代码转换为向后兼容的 JavaScript 语法(不过这里尽量不讲 ES6 的语法,ES6 单独抽离出了几篇文章)
加上下面这句开启严格模式 必须写在第一行
"use strict";
如果 'use strict'
放在 JS 文件首行,则整个 JS 文件都将以严格模式运行;(如果该句不在首行,则无效);需要特别注意多个文件合并成一个文件的情况,此情况下,提供一个方法,每个文件使用匿名函数自执行,将 'use strict'
放在函数第一行,表示整个函数为严格模式,函数以外在为正常模式;
定义变量
JavaScript 是一门弱类型语言
var num = 10;
ES6 添加了如下两种类型用来声明变量
const
用来声明常量
let
只在所在的代码块内有效
var 和 let 的区别
var
:变量提升(无论声明在何处,都会被提至其所在作用域的顶部)
let
:无变量提升(未到 let
声明时,是无法访问该变量的)所以局部变量都尽量使用 let
去定义
作用域
如果两个函数使用了相同的变量名,只要在函数内部就不冲突
function aaa() {
let x = 10;
}
function bbb() {
let x = 20;
}
// 内部函数可以访问外部函数
function aaa() {
let x = 10;
let c = function bbb() {
let y = x;
y++;
return y;
}
console.log(c());
}
内部变量与外部变量重名,优先使用内部变量
全局变量
默认所有的全局变量都会自动绑定在 window
对象下,这个 window
对象就代表浏览器;例如这个 alert
本身也是 window
的一个变量
let x = 100;
window.alert(x);
//可以直接把这个函数传给一个对象
let new_alert = window.alert;
new_alert(x);
//甚至可以直接重写方法
window.alert = function(){
};
综上,由于全局变量都会绑定到 window
上,所以为了避免冲突,使用以下规范
- 把自己的代码全部放在自己定义的命名空间中
- 一般用大写表示常量(虽然有
const
关键字,但是因为是引用类型所以对象的属性可以被修改,就像 Java 的final
关键字一样)
"use strict";
// 唯一全局变量
const alsritter = {}
// 定义全局变量
alsritter.NAME = 'alsritter'
alsritter.GENDER = 'male'
alsritter.add = function (a,b) {
console.log(a + "hello JavaScript!" + b)
}
//使用
alsritter.add('张三','李四')
比较运算符
=
== //等于(类型不同也会相等 例如数字与字符串 9 "9" )
=== //绝对等于(类型一样,值一样 一般用这个)
//NaN与所有数值都不相等,包括自己(所以只能通过 isNaN 这个函数比较)
//尽量避免使用浮点数进行运算,存在精度问题
//如果要比较最好加上使用绝对值
Math.abs(1/3 - (1 - 2/3)) < 0.00001
null
和 undefined
一个是空,一个是未定义,当定义了一个变量而未使用过则是 null
,从未使用过且是通过 变量提升 创建的对象则是 undefined
流程控制
if 判断
let a = 100;
if (a<20){
console.log("小于20");
}else if(a<50){
console.log("小于50");
}else {
console.log("其他");
}
switch
//生成从minNum到maxNum的随机数
function randomNum(minNum, maxNum) {
switch (arguments.length) {
case 1:
return parseInt(Math.random() * minNum + 1, 10);
break;
case 2:
return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10);
break;
default:
return 0;
break;
}
}
while 循环
while(age < 100){
age = age + 1;
console.log(age);
}
for 循环
for(let i = 0; i<100; i++){
console.log(i);
}
数组循环
const arr = [1, 2, 3, 4, 5];
arr.forEach(((value, index) => {
console.log(value +' '+ index);
}));
// 或采用传统的forEach(注意arrKey是下标)
for (let arrKey in arr) {
console.log(arr[arrKey]);
}
//ES6新出了一个遍历关键字(of)直接可以访问值
for (let number of arr) {
console.log(number)
}
数据类型
typeof 123
"number"
typeof 's'
"string"
typeof true
"boolean"
typeof NaN
"number"
typeof []
"object"
typeof {}
"object"
typeof Math.abs
"function"
typeof undefined
"undefined"
Number 类型
JS 不区分小数和整数
123 //整数
123.1 //浮点数
1.123e3 //科学计数法
-99 //复数
NaN // not a number NaN与所有数值都不相等,包括自己(所以只能通过 isNaN 这个函数比较)
Infinity //表示无限大
生成随机数
Math.ceil(); //向上取整。
Math.floor(); //向下取整。
Math.round(); //四舍五入。
Math.random(); //0.0 ~ 1.0 之间的一个伪随机数。【包含0不包含1】 //比如0.8647578968666494
Math.ceil(Math.random()*10); // 获取从 1 到 10 的随机整数 ,取0的概率极小。
Math.round(Math.random()); //可均衡获取 0 到 1 的随机整数。
Math.floor(Math.random()*10); //可均衡获取 0 到 9 的随机整数。
Math.round(Math.random()*10); //基本均衡获取 0 到 10 的随机整数,其中获取最小值 0 和最大值 10 的几率少一半。
生成[n,m]的随机整数
//生成从 minNum 到 maxNum 的随机数
function randomNum(minNum, maxNum) {
switch (arguments.length) {
case 1:
return parseInt(Math.random() * minNum + 1, 10);
break;
case 2:
return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10);
break;
default:
return 0;
break;
}
}
字符串 String
正常字符串使用单引号或双引号包裹(注意转移字符 \n
\t
\'
\uxxx
(Unicode字符))
模板字符串(ES6里的新特性)
let name = 'alsritter';
let msg = `你好${name}`
常用的字符串方法
let name = 'alsritter';
console.log(name[0]);
console.log(name.length);
//大小写转换
// toLowerCase 转换成小写
// toUpperCase 转换成大写
console.log(name.toUpperCase());
//获取指定的下标
console.log(name.indexOf('er'));
//获取子字符串 包括3不不包括8 [3,8)
console.log(name.substring(3, 8));
// 字符串匹配
// 规定要检索的字符串值。
stringObject.match(searchvalue)
// 或使用正则表达式
stringObject.match(regexp)
// trim() 方法会从一个字符串的两端删除空白字符。
// 在这个上下文中的空白字符是所有的空白字符(space, tab, no-break space 等)
// 以及所有行终止符字符(如 LF,CR等)
console.log(' hello world '.trim());
数组 Array
const arr = [1, 2, 3, 4, 5];
// 多维数组
let arr02 = [[1,2,3],[2,3],[1,2]];
// 长度
arr.length
// 通过元素获得下标索引
arr.indexOf('x')
// 截取数组的部分
arr.slice(3,7)
// 该方法向/从数组中添加/删除项目,然后返回被删除的项目。
// | 参数 | 描述 |
// | --------------- | --------------------------------------------------------------------- |
// | index | 必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。 |
// | howmany | 必需。要删除的项目数量。如果设置为 0,则不会删除项目。 |
// | item1,...,itemX | 可选。向数组添加的新项目。 |
arrayObject.splice(index,howmany,item1,.....,itemX)
// 例删除第10个元素和第11个元素
array.splice(10,2)
// 就是在数组末尾添加元素,并返回新的长度
arr.push(3,7)
// 弹出最后一个元素
arr.pop()
// 方法可向数组的开头添加一个或更多元素,并返回新的长度
arr.unshift(1,2,3,4,5,7)
// 弹出第一个元素
arr.shift()
// sort排序
arr.sort();
//如果第一个自变量小于第二个自变量,则为负值;如果相等则为零;大于为正数
arr.sort((a,b)=>{
return a - b;
});
// 元素反转
arr.reverse()
// 数组拼接
// 注意,这个 concat 并没有改变原本的数组,而是返回一个拼接后的数组
let arr2 = arr.concat([1,2,3,4])
// join连接 使用特定的字符串连接
const arr = [1, 2, 3, 4, 5];
console.log(arr.join('-'));
// 输出-->
// 1-2-3-4-5
下面一些方法也经常用到
some()
方法用于检测数组中的元素是否满足指定条件;该方法会依次执行数组的每个元素;如果有一个元素满足条件,则表达式返回 true
,剩余的元素不会再执行检测;如果没有满足条件的元素,则返回 false
。
// 检测数组中是否有元素大于 18。
var ages = [3, 10, 18, 20];
function myFunction() {
document.getElementById("demo").innerHTML = ages.some(function (age) {
return age >= 18;
});
}
filter()
方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
var ages = [32, 33, 16, 40];
// 参数是一个回调函数,回调函数返回值是一个true
function myFunction() {
document.getElementById("demo").innerHTML = ages.filter(function(age) {
return age >= 18;
})
}
对象 Object
JavaScript 中的所有的键都是字符串,值是任意对象,所以可以这样取值 person['age']
;
使用一个不存在的对象属性不会报错而是会显示 undefined
var person = {
name:"alsritter",
age:3,
tags:['js','java','web','...']
}
// 动态的删减属性
delete person.name
// 动态的添加属性
person.sex = '男'
// 判断属性值是否在这个对象中
'age' in person
-->
true
//继承
'toString' in person
-->
true
//判断是否是自身的方法
person.hasOwnProperty('toString')
-->
false
Map 和 Set
这是 ES6 的新特性
// Map
let map = new Map([['tom',100],['jack',90],['jimmy',40]]);
map.set('lily',30);
console.log(map.get('tom'));
map.delete('tom');
// Set 无序不重复的集合
let set = new Set([1,2,3,4,5]);
set.add(6);
set.delete(4);
//判断是否存在某个元素
set.has(3);
-->
true
日期类型 Date
let now = new Date();
now.getFullYear();//年
now.getMonth();//星期
now.getDay();//星期几
now.getDate();//日
now.getHours();//时
now.getMinutes();//分
now.getSeconds();//秒
now.getTime();//获取时间戳(全世界统一)
//时间戳转成时间
let time = new Date(1590301998162);
//本地时间
console.log(now.toLocaleString());
console.log(now.toLocaleDateString());
-->
5/24/2020, 2:55:32 PM
5/24/2020
Json
在 JavaScript 中一切皆为对象,任何 JS 支持的格式都可以用 Json 来表示;
- 对象都用
{}
- 数组用
[]
- 所有的键值对都是用
key:value
let user = {
name:'alsritter',
age:20,
sex:'male'
}
//对象转换为json字符串
let str = JSON.stringify(user);
console.log(str);
//把对象转成对象
let o = JSON.parse(str);
console.log(o);
iterator 迭代器
of
关键字是 ES6 的特性,尽量使用这个,另一个 for in
有很多早期的 Bug;而遍历 Map,Set 只能用 iterator
let map = new Map([['tom',100],['jack',90],['jimmy',40]]);
for (let mapElement of map) {
console.log(mapElement);
}
let set = new Set([1,2,3,4,5]);
for (let number of set) {
console.log(number);
}
函数和方法
放在对象里叫做方法;放在外面叫做函数
一旦执行到 return
代表函数结束,返回结果;如果没有执行 return
,函数执行完也会返回结果,结果就是undefined
定义函数
最普通的方式
function abs(x) {
if (x>=0){
return x;
}else{
return -x;
}
}
console.log(abs(-10));
-->
10
以定义对象的形式定义函数,但是效果与上面那种是一样的;function (x){....}
是一个匿名函数,但是可以把结果返回给 abs
,通过 abs
就可以调用
let abs = function (x) {
if (x>=0){
return x;
}else{
return -x;
}
}
console.log(abs(-10));
定义方法
"use strict";
// 唯一全局变量
const alsritter = {
name:'alsritter',
birth:2000,
//方法(因为是在对象的里面,所以叫做方法)
age:function () {
//方法 当前时间-birth
let now = new Date().getFullYear();
//注意这里也有this关键字
return now - this.birth;
}
}
//测试(调用方法一定要带括号)
console.log(alsritter.age());
尽量不要在这种写在外面的写法使用 this
关键字,因为 this
是结合上下文的动态更换的,如果在外部调用了这个方法则是使用的 window
对象
function getAge() {
//方法 当前时间-birth
let now = new Date().getFullYear();
//注意这里也有this关键字
return now - this.birth;
}
// 唯一全局变量
const alsritter = {
name:'alsritter',
birth:2000,
//注意这里不需要加括号
age:getAge // 这个方法可以用来计算年龄
}
//测试
console.log(alsritter.age());
而且 JS 有种创建 “Class” 的方式就是这样使用 this
作为构造函数调用,如下
let x = 100 // 这里定义一个全局对象为 100
function test() {
this.x = 1; // 这个 x 是构造方法里面的属性
}
let obj = new test();
console.log(obj.x); // 输出 1
console.log(x); // 输出 100
上文提到尽量不要在全局方法里使用 this
一般使用使用 apply
方法代替(apply
是所有函数/方法都有的方法);其作用是 改变函数的调用对象。它的第一个参数就表示改变后的调用这个函数的对象。因此,这时 this
指的就是这第一个参数。
function getAge() {
//方法 当前时间-birth
let now = new Date().getFullYear();
//注意这里也有this关键字
return now - this.birth;
}
//传入的第一个参数是 this 的对象,第二个是参数(但是不需要参数,所以这里为空)
console.log(getAge.apply(alsritter,[]));
可变长参数
以前实现多参数使用的是 arguments
关键字
if(arguments.length>2){
for(let i = 2;i<arguments.length;i++){
...
}
}
在 ES6 之后可以像 Java 一样使用 ...
来定义
let abs = function (...items) {
console.log(items);
}
abs(1,2,3,4,5,6);
-->
[ 1, 2, 3, 4, 5, 6 ]
返回一个数组(注意,这个items是自定义的变量名)
判断传入类型
使用关键字 typeof
let abs = function (x) {
//手动抛出异常
if(typeof x!== 'number'){
throw 'not a number!';
}
if (x>=0){
return x;
}else{
return -x;
}
}
console.log(abs('-10'));
// -->报错
// throw 'not a number!';
// ^
// not a number!
// (Use `node --trace-uncaught ...` to show where the exception was thrown)
传入多个参数的情况(使用关键字 arguments
)
let abs = function (x) {
if(arguments.length>1){
throw 'arguments oversized!';
}
if (x>=0){
return x;
}else{
return -x;
}
}
// console.log(abs(1,2));
//
// -->报错
// throw 'arguments oversized!';
// ^
// arguments oversized!
// (Use `node --trace-uncaught ...` to show where the exception was thrown)